#pragma comment(lib, "..\\..\\lib\\Debug\\Utils-d.lib")

# include <iostream>
# include <SDL/SDL.h>
# include <SDL/SDL_image.h>
# include "config.h"
# include "debug.h"
# include "Utils\Rect.h"
# include "Utils\Color.h"
# include "Utils\\Surface.h"
# include "Utils\\ResGroupManager.h"
# include "Utils\\AWindow.h"
# include "Utils\\IScreen.h"

using namespace SDL;
using namespace UTILS;

#pragma region Color
static void printColor(SDL_Color const& _color)
{
	std::cout << "Color: {"
			  << (int)_color.r << ", " << (int)_color.g << ", " << (int)_color.b
			  << "}" << std::endl;
}

static void testColor()
{
	SDL_Color c1 = { 90, 150, 13};
	SDL::UTILS::Color c2(c1);

	printColor(c1);
	printColor(c2.color);

	Uint32 c3 = c2.ToUint32();
	std::cout << c3 << std::endl;
}
#pragma endregion
#pragma region Surface / Color / Rect
static void printSurface(SDL_Surface* _surface)
{
	if (_surface == NULL)
		return ;

	for (int y = 0; y < _surface->h; y++)
	{
		for (int x = 0; x < _surface->w; x++)
		{
			std::cout << (char)SDL::UTILS::Surface::GetPixel(_surface, x, y);
		}
		std::cout << std::endl;
	}
}

static void Loop(SDL_Surface* _screen)
{
	SDL::UTILS::Surface mana(IMG_Load("Mana-sama 10.jpg"));
	SDL::UTILS::Surface kana(IMG_Load("Moon Kana 01.jpg"));
	SDL::UTILS::Surface boss(IMG_Load("MyBossMyHeroe.jpg"));
	SDL::UTILS::Surface colorkey(IMG_Load("colorkey.png"));
	colorkey.SetColorKey(0xFFFFFF);
	colorkey.SetAlpha(128);
	mana.SetAlpha(200);
	SDL::UTILS::Surface ckcopy(colorkey);
	SDL::UTILS::Rect rMana(0, 0);
	SDL::UTILS::Rect rKana(mana.w, 0);
	SDL::UTILS::Rect rBoss(mana.w, kana.h);
	SDL::UTILS::Rect rCopy(0, kana.h);
	SDL_Event e;
	SDL::UTILS::Color sdlcolor(255, 0, 128);
	Uint32 color = sdlcolor.ToUint32();
	ckcopy.SetColorKey(0);
	ckcopy.SetAlpha(SDL_ALPHA_OPAQUE);
	bool quit = false;

	for (int y = 32; y < ckcopy.h - 32; y++)
	{
		for (int x = 32; x < ckcopy.w - 32; x++)
		{
			if (ckcopy.GetPixel(x, y) == 0xFFFFFF)
				ckcopy.SetPixel(0x00FFFF, x, y);
		}
	}

	SDL::UTILS::Surface manaCopy(mana);

	std::cout << "MANA" << ((mana == manaCopy) ? " == " : " != ")
			  << "MANA_COPY" << std::endl;
	std::cout << "CK" << ((colorkey == ckcopy) ? " == " : " != ")
			  << "CK_COPY" << std::endl;

	while (!quit)
	{
		SDL_PollEvent(&e);
		switch (e.type)
		{
		case SDL_QUIT:
			quit = true;
			break ;
		case SDL_KEYDOWN:
			if (e.key.keysym.sym == SDLK_ESCAPE)
				quit = true;
			break ;
		}

		SDL_FillRect(_screen, NULL, color);
		SDL::UTILS::Surface::BlitSurface(mana.surface, NULL, _screen, &rMana);
		SDL::UTILS::Surface::BlitSurface(kana.surface, NULL, _screen, &rKana);
		SDL::UTILS::Surface::BlitSurface(manaCopy.surface, NULL, _screen, &rKana);
		SDL::UTILS::Surface::BlitSurface(boss.surface, NULL, _screen, &rBoss);
		SDL::UTILS::Surface::BlitSurface(colorkey.surface, NULL, _screen, &rBoss);
		SDL::UTILS::Surface::BlitSurface(ckcopy.surface, NULL, _screen, &rCopy);
		SDL_Flip(_screen);
	}
}

static void testSurface()
{
	SDL_Init(SDL_INIT_VIDEO);
	SDL_Surface* screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
	if (screen == NULL)
	{
		FATAL_ERR(SDL_GetError());
		return ;
	}

	Loop(screen);

	SDL_Quit();
}
#pragma endregion
#pragma region ResGroupManager
static void testResGroupManager()
{
	ResGroup* def = ResGroupManager::Instance()["default"];
	if (def == NULL)
	{
		std::cout << "Error: Default group not found" << std::endl;
		return ;
	}
	def->AddResource("mana", "Mana-sama 10.jpg");
	def->AddResource("Fake mana", "Mana-sama 142.jpg");

	SDL_Init(SDL_INIT_VIDEO);

	Surface mana, manaFake;
	Resource const* r = (*def)["mana"];
	if (r != NULL)
		mana.surface = IMG_Load(r->Path.c_str());
	r = (*def)["Fake mana"];
	if (r != NULL)
		manaFake.surface = IMG_Load(r->Path.c_str());

	std::cout << "Mana: " << ((mana.surface == NULL) ? "NULL" : "NOT NULL")
			  << std::endl;
	std::cout << "Mana Fake: " << ((manaFake.surface == NULL) ? "NULL" : "NOT NULL")
			  << std::endl;
	
	SDL_Quit();
}
#pragma endregion

struct OptionsArgs : public IArgs
{
public:
	SDL_Surface* Screen;
	SDL_Event& Event;
	bool& Show;
	int choice;

public:
	OptionsArgs(SDL_Surface* _screen, SDL_Event& _event, bool& _show)
		: IArgs(), Screen(_screen), Event(_event), Show(_show), choice(1)
	{
	}

	virtual ~OptionsArgs() {}
};

class Options : public IScreen
{
private:
	Surface m_background;
	Rect m_pos;

public:
	Options(IArgs* _args) : IScreen(_args), m_pos(400-128, 300-128)
	{
		ResGroup* res = ResGroupManager::Instance()["Options"];
		if (res == NULL)
		{
			ResGroupManager& rgm = ResGroupManager::Instance();
			res = new ResGroup("MainScreen");
			res->AddResource("Background", "OptionsBackground.png");
			rgm.Add("Options", res);
		}
		m_background.surface = IMG_Load((*res)["Background"]->Path.c_str());
	}

	virtual ~Options() {}

	virtual void Draw()
	{
		OptionsArgs* oa = dynamic_cast<OptionsArgs*>(m_args);
		m_background.BlitSurface(NULL, oa->Screen, &m_pos);
	}

	virtual void Exec()
	{
		OptionsArgs* oa = dynamic_cast<OptionsArgs*>(m_args);
		switch (oa->Event.type)
		{
		case SDL_KEYDOWN:
			switch (oa->Event.key.keysym.sym)
			{
			case SDLK_1:
			case SDLK_KP1:
				oa->choice = 1;
				break ;

			case SDLK_2:
			case SDLK_KP2:
				oa->choice = 2;
				break ;

			case SDLK_3:
			case SDLK_KP3:
				oa->Show = false;
				break ;
			}
			break ;
		}
	}
};

struct MainArgs : public IArgs
{
public:
	SDL_Surface* Screen;
	SDL_Event& Event;
	bool& Quit;
	int Option;

public:
	MainArgs(SDL_Surface* _screen, SDL_Event& _event, bool& _quit)
		: Screen(_screen), Event(_event), Quit(_quit), Option(0)
	{
	}

	virtual ~MainArgs() {}
};

class MainScreen : public IScreen
{
private:
	Surface m_background;
	Options* m_optionsScreen;
	OptionsArgs* m_optionsArgs;
	bool m_showOptions;

public:
	MainScreen(IArgs* _args) : IScreen(_args),
		m_optionsScreen(NULL), m_optionsArgs(NULL), m_showOptions(false)
	{
		ResGroup* res = ResGroupManager::Instance()["MainScreen"];
		if (res == NULL)
		{
			ResGroupManager& rgm = ResGroupManager::Instance();
			res = new ResGroup("MainScreen");
			res->AddResource("Background", "MainBackground.png");
			res->AddResource("Background2", "MainBackground2.png");
			rgm.Add("MainScreen", res);
		}
		MainArgs* ma = dynamic_cast<MainArgs*>(m_args);
		m_background.surface = IMG_Load((*res)["Background"]->Path.c_str());
		m_optionsArgs = new OptionsArgs(ma->Screen, ma->Event, m_showOptions);
		m_optionsScreen = new Options(m_optionsArgs);
	}

	virtual ~MainScreen() {}

	void Draw()
	{
		MainArgs* ma = dynamic_cast<MainArgs*>(m_args);
		m_background.BlitSurface(NULL, ma->Screen, NULL);
		if (m_showOptions == true)
		{
			m_optionsScreen->Draw();
		}
	}

	void Exec()
	{
		MainArgs* ma = dynamic_cast<MainArgs*>(m_args);
		if (m_showOptions == false)
		{
			switch (ma->Event.type)
			{
			case SDL_KEYDOWN:
				switch (ma->Event.key.keysym.sym)
				{
				case SDLK_ESCAPE:
					ma->Quit = true;
					break;

				case SDLK_1:
				case SDLK_KP1:
					ma->Option = 1;
					break ;

				case SDLK_2:
				case SDLK_KP2:
					m_showOptions = true;
					break ;

				case SDLK_3:
				case SDLK_KP3:
					ma->Option = 3;
					break ;
				}
				break ;
			}
		}
		else
		{
			int choice = m_optionsArgs->choice;
			m_optionsScreen->Exec();
			if (choice != m_optionsArgs->choice)
			{
				choice = m_optionsArgs->choice;
				ResGroup* res = ResGroupManager::Instance()["MainScreen"];
				if (choice == 1)
					m_background.surface = IMG_Load((*res)["Background"]->Path.c_str());
				else if (choice == 2)
					m_background.surface = IMG_Load((*res)["Background2"]->Path.c_str());
			}
		}
	}
};

struct GameArgs : public IArgs
{
public:
	SDL_Surface* Screen;
	SDL_Event& Event;
	bool BackToMain;

public:
	GameArgs(SDL_Surface* _screen, SDL_Event& _event)
		: Screen(_screen), Event(_event), BackToMain(false)
	{
	}

	virtual ~GameArgs() {}
};

class GameScreen : public IScreen
{
private:
	Surface m_background;

public:
	GameScreen(IArgs* _args) : IScreen(_args)
	{
		ResGroup* res = ResGroupManager::Instance()["GameScreen"];
		if (res == NULL)
		{
			ResGroupManager& rgm = ResGroupManager::Instance();
			res = new ResGroup("GameScreen");
			res->AddResource("Background", "GameBackground.png");
			rgm.Add("GameScreen", res);
		}
		m_background.surface = IMG_Load((*res)["Background"]->Path.c_str());
	}

	virtual ~GameScreen() {}

	virtual void Draw()
	{
		GameArgs* ga = dynamic_cast<GameArgs*>(m_args);
		m_background.BlitSurface(NULL, ga->Screen, NULL);
	}

	virtual void Exec()
	{
		GameArgs* ga = dynamic_cast<GameArgs*>(m_args);
		switch (ga->Event.type)
		{
		case SDL_KEYDOWN:
			switch (ga->Event.key.keysym.sym)
			{
			case SDLK_ESCAPE:
				ga->BackToMain = true;
				break ;
			}
			break ;
		}
	}
};

class Window : public AWindow
{
private:
	IScreen* m_currentScreen;
	SDL_Event m_event;
	bool m_quit;
	MainArgs* m_mainArgs;
	int m_currentScreenId;
	GameArgs* m_gameArgs;

public:
	Window()
		: m_mainArgs(NULL), m_currentScreenId(0)
	{
		m_quit = false;
	}
	virtual ~Window() { delete m_mainArgs; }

	int Exec()
	{
		m_mainArgs = new MainArgs(m_screen, m_event, m_quit);
		m_currentScreen = new MainScreen(m_mainArgs);
		m_gameArgs = new GameArgs(m_screen, m_event);

		while (!m_quit)
		{
			while (SDL_PollEvent(&m_event))
			{
				switch (m_event.type)
				{
				case SDL_QUIT:
					m_quit = true;
					break ;
					
				default:
					break ;
				}

				m_currentScreen->Exec();
			}

			switch (m_currentScreenId)
			{
			case 0:
				{
					switch (m_mainArgs->Option)
					{
					case 1:
						m_currentScreenId = 1;
						delete m_currentScreen;
						m_currentScreen = new GameScreen(m_gameArgs);
						m_mainArgs->Option = 0;
						break ;

					case 2:
						break ;

					case 3:
						m_quit = true;
						break ;

					case 0:
					default:
						break ;
					}
				}
			case 1:
				{
					if (m_gameArgs->BackToMain == true)
					{
						delete m_currentScreen;
						m_gameArgs->BackToMain = false;
						m_currentScreen = new MainScreen(m_mainArgs);
						m_currentScreenId = 0;
					}
				}
			}

			SDL_FillRect(m_screen, NULL, 0);
			m_currentScreen->Draw();
			SDL_Flip(m_screen);
		}
		return (EXIT_SUCCESS);
	}
};

static void testAWindow()
{
	Window w;
	w.Init(SDLConfig());
	w.Exec();
}

int main(int, char**)
{
	//testColor();
	//testSurface();
	//testResGroupManager();
	testAWindow();
	std::cout << "Press enter to continue..." << std::endl;
	getchar();
	return (EXIT_SUCCESS);
}
